package dao

import (
	"context"

	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"

	"goldtree/internal/entity"
)

// TagDao 标签数据访问对象
type TagDao struct{}

var Tag = TagDao{}

// Insert 创建标签
func (dao *TagDao) Insert(ctx context.Context, tag *entity.Tag) (int64, error) {
	// 排除ID字段，让数据库自动生成
	result, err := g.DB().Model("tags").Ctx(ctx).Data(tag).OmitEmpty().Insert()
	if err != nil {
		return 0, err
	}
	return result.LastInsertId()
}

// Update 更新标签
func (dao *TagDao) Update(ctx context.Context, id int, tag *entity.Tag) error {
	tag.UpdatedAt = gtime.Now()
	_, err := g.DB().Model("tags").Ctx(ctx).Where("id", id).Data(tag).Update()
	return err
}

// Delete 删除标签
func (dao *TagDao) Delete(ctx context.Context, id int) error {
	// 先删除股票标签关联
	_, err := g.DB().Model("stock_tags").Ctx(ctx).Where("tag_id", id).Delete()
	if err != nil {
		return err
	}
	
	// 删除标签
	_, err = g.DB().Model("tags").Ctx(ctx).Where("id", id).Delete()
	return err
}

// GetById 根据ID获取标签
func (dao *TagDao) GetById(ctx context.Context, id int) (*entity.Tag, error) {
	var tag *entity.Tag
	err := g.DB().Model("tags").Ctx(ctx).Where("id", id).Scan(&tag)
	if err != nil {
		return nil, err
	}
	return tag, nil
}

// GetByName 根据名称获取标签
func (dao *TagDao) GetByName(ctx context.Context, name string) (*entity.Tag, error) {
	var tag *entity.Tag
	err := g.DB().Model("tags").Ctx(ctx).Where("name", name).Scan(&tag)
	if err != nil {
		return nil, err
	}
	return tag, nil
}

// GetList 获取标签列表
func (dao *TagDao) GetList(ctx context.Context, page, limit int, conditions ...interface{}) ([]*entity.Tag, error) {
	model := g.DB().Model("tags").Ctx(ctx)
	
	// 添加查询条件
	if len(conditions) > 0 {
		model = model.Where(conditions[0], conditions[1:]...)
	}
	
	var tags []*entity.Tag
	err := model.Order("sort_order ASC, created_at DESC").Limit((page-1)*limit, limit).Scan(&tags)
	if err != nil {
		return nil, err
	}
	return tags, nil
}

// GetCount 获取标签总数
func (dao *TagDao) GetCount(ctx context.Context, conditions ...interface{}) (int, error) {
	model := g.DB().Model("tags").Ctx(ctx)
	
	// 添加查询条件
	if len(conditions) > 0 {
		model = model.Where(conditions[0], conditions[1:]...)
	}
	
	count, err := model.Count()
	if err != nil {
		return 0, err
	}
	return count, nil
}

// GetActiveTags 获取激活的标签列表
func (dao *TagDao) GetActiveTags(ctx context.Context) ([]*entity.Tag, error) {
	var tags []*entity.Tag
	err := g.DB().Model("tags").Ctx(ctx).Where("is_active", true).Order("sort_order ASC, created_at DESC").Scan(&tags)
	if err != nil {
		return nil, err
	}
	return tags, nil
}

// GetByCategory 根据分类获取标签列表
func (dao *TagDao) GetByCategory(ctx context.Context, category string) ([]*entity.Tag, error) {
	var tags []*entity.Tag
	err := g.DB().Model("tags").Ctx(ctx).
		Where("category", category).
		Where("is_active", true).
		Order("sort_order ASC, created_at DESC").
		Scan(&tags)
	if err != nil {
		return nil, err
	}
	return tags, nil
}

// GetCategoryList 获取标签分类列表
func (dao *TagDao) GetCategoryList(ctx context.Context) ([]string, error) {
	var categories []string
	err := g.DB().Model("tags").Ctx(ctx).Fields("DISTINCT category").Where("is_active", true).Scan(&categories)
	if err != nil {
		return nil, err
	}
	return categories, nil
}

// GetChildTags 获取子标签列表
func (dao *TagDao) GetChildTags(ctx context.Context, parentId int) ([]*entity.Tag, error) {
	var tags []*entity.Tag
	err := g.DB().Model("tags").Ctx(ctx).
		Where("parent_id", parentId).
		Where("is_active", true).
		Order("sort_order ASC, created_at DESC").
		Scan(&tags)
	if err != nil {
		return nil, err
	}
	return tags, nil
}

// GetRootTags 获取根标签列表（没有父标签的标签）
func (dao *TagDao) GetRootTags(ctx context.Context) ([]*entity.Tag, error) {
	var tags []*entity.Tag
	err := g.DB().Model("tags").Ctx(ctx).
		Where("parent_id IS NULL OR parent_id = 0").
		Where("is_active", true).
		Order("sort_order ASC, created_at DESC").
		Scan(&tags)
	if err != nil {
		return nil, err
	}
	return tags, nil
}

// IsNameExists 检查标签名称是否存在
func (dao *TagDao) IsNameExists(ctx context.Context, name string) (bool, error) {
	count, err := g.DB().Model("tags").Ctx(ctx).Where("name", name).Count()
	if err != nil {
		return false, err
	}
	return count > 0, nil
}

// UpdateSortOrder 更新标签排序
func (dao *TagDao) UpdateSortOrder(ctx context.Context, id int, sortOrder int) error {
	_, err := g.DB().Model("tags").Ctx(ctx).
		Where("id", id).
		Data(g.Map{"sort_order": sortOrder, "updated_at": gtime.Now()}).
		Update()
	return err
}

// StockTagDao 股票标签关联数据访问对象
type StockTagDao struct{}

var StockTag = StockTagDao{}

// Insert 创建股票标签关联
func (dao *StockTagDao) Insert(ctx context.Context, stockTag *entity.StockTag) (int64, error) {
	result, err := g.DB().Model("stock_tags").Ctx(ctx).Data(stockTag).OmitEmpty().Insert()
	if err != nil {
		return 0, err
	}
	return result.LastInsertId()
}

// BatchInsert 批量创建股票标签关联
func (dao *StockTagDao) BatchInsert(ctx context.Context, stockTags []*entity.StockTag) error {
	_, err := g.DB().Model("stock_tags").Ctx(ctx).Data(stockTags).Insert()
	return err
}

// Delete 删除股票标签关联
func (dao *StockTagDao) Delete(ctx context.Context, id int) error {
	_, err := g.DB().Model("stock_tags").Ctx(ctx).Where("id", id).Delete()
	return err
}

// DeleteByStockAndTag 根据股票代码和标签ID删除关联
func (dao *StockTagDao) DeleteByStockAndTag(ctx context.Context, stockCode string, tagId int) error {
	_, err := g.DB().Model("stock_tags").Ctx(ctx).
		Where("stock_code", stockCode).
		Where("tag_id", tagId).
		Delete()
	return err
}

// DeleteByStock 删除股票的所有标签关联
func (dao *StockTagDao) DeleteByStock(ctx context.Context, stockCode string) error {
	_, err := g.DB().Model("stock_tags").Ctx(ctx).Where("stock_code", stockCode).Delete()
	return err
}

// DeleteByTag 删除标签的所有股票关联
func (dao *StockTagDao) DeleteByTag(ctx context.Context, tagId int) error {
	_, err := g.DB().Model("stock_tags").Ctx(ctx).Where("tag_id", tagId).Delete()
	return err
}

// GetByStockCode 根据股票代码获取标签关联列表
func (dao *StockTagDao) GetByStockCode(ctx context.Context, stockCode string) ([]*entity.StockTag, error) {
	var stockTags []*entity.StockTag
	err := g.DB().Model("stock_tags").Ctx(ctx).
		Where("stock_code", stockCode).
		Order("assigned_at DESC").
		Scan(&stockTags)
	if err != nil {
		return nil, err
	}
	return stockTags, nil
}

// GetByTagId 根据标签ID获取股票关联列表
func (dao *StockTagDao) GetByTagId(ctx context.Context, tagId int, page, limit int) ([]*entity.StockTag, error) {
	var stockTags []*entity.StockTag
	
	if page > 0 && limit > 0 {
		err := g.DB().Model("stock_tags").Ctx(ctx).
			Where("tag_id", tagId).
			Order("assigned_at DESC").
			Limit((page-1)*limit, limit).
			Scan(&stockTags)
		return stockTags, err
	} else {
		// 不分页，获取所有关联
		err := g.DB().Model("stock_tags").Ctx(ctx).
			Where("tag_id", tagId).
			Order("assigned_at DESC").
			Scan(&stockTags)
		return stockTags, err
	}
}

// GetCountByTagId 根据标签ID获取股票关联总数
func (dao *StockTagDao) GetCountByTagId(ctx context.Context, tagId int) (int, error) {
	count, err := g.DB().Model("stock_tags").Ctx(ctx).Where("tag_id", tagId).Count()
	if err != nil {
		return 0, err
	}
	return count, nil
}

// IsRelationExists 检查股票标签关联是否存在
func (dao *StockTagDao) IsRelationExists(ctx context.Context, stockCode string, tagId int) (bool, error) {
	count, err := g.DB().Model("stock_tags").Ctx(ctx).
		Where("stock_code", stockCode).
		Where("tag_id", tagId).
		Count()
	if err != nil {
		return false, err
	}
	return count > 0, nil
}

// UpdateWeight 更新股票标签关联权重
func (dao *StockTagDao) UpdateWeight(ctx context.Context, id int, weight float64) error {
	_, err := g.DB().Model("stock_tags").Ctx(ctx).
		Where("id", id).
		Data(g.Map{"weight": weight}).
		Update()
	return err
}

// GetStocksByTag 根据标签获取股票列表（联表查询）
func (dao *StockTagDao) GetStocksByTag(ctx context.Context, tagId int, page, limit int) ([]map[string]interface{}, error) {
	var results []map[string]interface{}
	
	model := g.DB().Model("stock_tags st").Ctx(ctx).
		LeftJoin("stocks s", "st.stock_code = s.code").
		Fields("s.*, st.weight, st.assigned_at, st.assigned_by").
		Where("st.tag_id", tagId)
	
	if page > 0 && limit > 0 {
		err := model.Order("st.assigned_at DESC").Limit((page-1)*limit, limit).Scan(&results)
		return results, err
	} else {
		err := model.Order("st.assigned_at DESC").Scan(&results)
		return results, err
	}
}

// GetTagsByStock 根据股票获取标签列表（联表查询）
func (dao *StockTagDao) GetTagsByStock(ctx context.Context, stockCode string) ([]map[string]interface{}, error) {
	var results []map[string]interface{}
	
	err := g.DB().Model("stock_tags st").Ctx(ctx).
		LeftJoin("tags t", "st.tag_id = t.id").
		Fields("t.*, st.weight, st.assigned_at, st.assigned_by").
		Where("st.stock_code", stockCode).
		Where("t.is_active", true).
		Order("t.sort_order ASC, st.assigned_at DESC").
		Scan(&results)
	
	return results, err
}